package com.artoxian.application;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import org.apache.log4j.Logger;

import com.garmin.fit.Decode;
import com.garmin.fit.FitRuntimeException;
import com.garmin.fit.Mesg;
import com.garmin.fit.MesgBroadcaster;
import com.garmin.fit.MesgListener;

public class FileProcessor {
	private static Logger log = Logger.getLogger(FileProcessor.class);
	
	private List<String> exisitingActivityIds;
	
	public FileProcessor(List<String> exisitingActivityIds) throws IOException {	
		// Initialise variables
		this.exisitingActivityIds = exisitingActivityIds;
	}
	
	public void processDirectory(File directory) throws FileNotFoundException {
		// TODO check for nulls
		
		// Loop through the files in the directory
		for (File file : directory.listFiles()) {
			processFile(file);
		}
	}
	
	private void processFile(File file) throws FileNotFoundException {
		// Get the fileStream
		FileInputStream fileStream = new FileInputStream(file);
		
		log.info("Checking file: " + file.getAbsolutePath());
		
		// Check the integrity of the FIT file
		try {
			if (!Decode.checkIntegrity((InputStream) fileStream)) {
				throw new RuntimeException("FIT file integrity failed.");
			}
		} finally {
			try {
				fileStream.close();
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
		}
		
		log.info("Valid FIT file: " + file.getAbsolutePath());
	
		try {
			fileStream = new FileInputStream(file.getAbsolutePath());
		} catch (IOException e) {
			throw new RuntimeException("Error opening file " + file.getAbsolutePath() + " [2]");
		}
		
		// Add a listener for the current file
		MesgBroadcaster fileHandler = new MesgBroadcaster(new Decode());
		fileHandler.addListener((MesgListener) new MesgListenerImpl(file));
	
		try {
			fileHandler.run(fileStream);
		} catch (FitRuntimeException e) {
			System.err.print("Exception decoding file: " + file.getAbsolutePath());
			System.err.println(e.getMessage());
	
			try {
				fileStream.close();
			} catch (IOException f) {
				throw new RuntimeException(f);
			}
	
			return;
		}
	
		try {
			fileStream.close();
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}
	
	private class MesgListenerImpl implements MesgListener {
		private final Logger log = Logger.getLogger(MesgListenerImpl.class);
		
		private final String SESSION_MESSAGE = "session";
		private final String START_TIME_FIELD = "start_time";
		
		private final File file;
		
		public MesgListenerImpl(File file) {
			// Initialise internal variables
			this.file = file;
		}
		
		@Override
		public void onMesg(Mesg mesg) {
			// Check if the message is the session
			if (SESSION_MESSAGE.equals(mesg.getName())) {
				// Get the activity Id
				String activityId = mesg.getField(START_TIME_FIELD).getStringValue();
				
				// Save the file to pending if it doesn't already exist
				if (!exisitingActivityIds.contains(activityId)) {
					Application.getInstance().addPendingFile(file);
					log.info("New file to be uploaded: " + file.getAbsolutePath());
				} else {
					log.info("File already uploaded: " + file.getAbsolutePath());
				}
			}
		}
	}
}
